home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 10868 / 10868.xpi / modules / engines / history.js < prev    next >
Text File  |  2010-02-02  |  10KB  |  341 lines

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3.  *
  4.  * The contents of this file are subject to the Mozilla Public License Version
  5.  * 1.1 (the "License"); you may not use this file except in compliance with
  6.  * the License. You may obtain a copy of the License at
  7.  * http://www.mozilla.org/MPL/
  8.  *
  9.  * Software distributed under the License is distributed on an "AS IS" basis,
  10.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11.  * for the specific language governing rights and limitations under the
  12.  * License.
  13.  *
  14.  * The Original Code is Weave
  15.  *
  16.  * The Initial Developer of the Original Code is Mozilla.
  17.  * Portions created by the Initial Developer are Copyright (C) 2008
  18.  * the Initial Developer. All Rights Reserved.
  19.  *
  20.  * Contributor(s):
  21.  *  Dan Mills <thunder@mozilla.com>
  22.  *
  23.  * Alternatively, the contents of this file may be used under the terms of
  24.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  25.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  26.  * in which case the provisions of the GPL or the LGPL are applicable instead
  27.  * of those above. If you wish to allow use of your version of this file only
  28.  * under the terms of either the GPL or the LGPL, and not to allow others to
  29.  * use your version of this file under the terms of the MPL, indicate your
  30.  * decision by deleting the provisions above and replace them with the notice
  31.  * and other provisions required by the GPL or the LGPL. If you do not delete
  32.  * the provisions above, a recipient may use your version of this file under
  33.  * the terms of any one of the MPL, the GPL or the LGPL.
  34.  *
  35.  * ***** END LICENSE BLOCK ***** */
  36.  
  37. const EXPORTED_SYMBOLS = ['HistoryEngine'];
  38.  
  39. const Cc = Components.classes;
  40. const Ci = Components.interfaces;
  41. const Cu = Components.utils;
  42.  
  43. const GUID_ANNO = "weave/guid";
  44.  
  45. Cu.import("resource://gre/modules/XPCOMUtils.jsm");
  46. Cu.import("resource://weave/util.js");
  47. Cu.import("resource://weave/engines.js");
  48. Cu.import("resource://weave/stores.js");
  49. Cu.import("resource://weave/trackers.js");
  50. Cu.import("resource://weave/type_records/history.js");
  51.  
  52. // Create some helper functions to handle GUIDs
  53. function setGUID(uri, guid) {
  54.   if (arguments.length == 1)
  55.     guid = Utils.makeGUID();
  56.   Utils.anno(uri, GUID_ANNO, guid, "WITH_HISTORY");
  57.   return guid;
  58. }
  59. function GUIDForUri(uri, create) {
  60.   try {
  61.     // Use the existing GUID if it exists
  62.     return Utils.anno(uri, GUID_ANNO);
  63.   }
  64.   catch (ex) {
  65.     // Give the uri a GUID if it doesn't have one
  66.     if (create)
  67.       return setGUID(uri);
  68.   }
  69. }
  70.  
  71. function HistoryEngine() {
  72.   this._init();
  73. }
  74. HistoryEngine.prototype = {
  75.   __proto__: SyncEngine.prototype,
  76.   name: "history",
  77.   _displayName: "History",
  78.   description: "All the sites you've been to.  Take your awesomebar with you!",
  79.   logName: "History",
  80.   _recordObj: HistoryRec,
  81.   _storeObj: HistoryStore,
  82.   _trackerObj: HistoryTracker,
  83.  
  84.   _sync: Utils.batchSync("History", SyncEngine),
  85.  
  86.   _findDupe: function _findDupe(item) {
  87.     return GUIDForUri(item.histUri);
  88.   }
  89. };
  90.  
  91. function HistoryStore() {
  92.   this._init();
  93. }
  94. HistoryStore.prototype = {
  95.   __proto__: Store.prototype,
  96.   name: "history",
  97.   _logName: "HistStore",
  98.  
  99.   get _hsvc() {
  100.     let hsvc = Cc["@mozilla.org/browser/nav-history-service;1"].
  101.       getService(Ci.nsINavHistoryService);
  102.     hsvc.QueryInterface(Ci.nsIGlobalHistory2);
  103.     hsvc.QueryInterface(Ci.nsIBrowserHistory);
  104.     hsvc.QueryInterface(Ci.nsPIPlacesDatabase);
  105.     this.__defineGetter__("_hsvc", function() hsvc);
  106.     return hsvc;
  107.   },
  108.  
  109.   get _db() {
  110.     return this._hsvc.DBConnection;
  111.   },
  112.  
  113.   get _visitStm() {
  114.     this._log.trace("Creating SQL statement: _visitStm");
  115.     let stm = this._db.createStatement(
  116.       "SELECT visit_type type, visit_date date " +
  117.       "FROM moz_historyvisits_view " +
  118.       "WHERE place_id = (" +
  119.         "SELECT id " +
  120.         "FROM moz_places_view " +
  121.         "WHERE url = :url) " +
  122.       "ORDER BY date DESC LIMIT 10");
  123.     this.__defineGetter__("_visitStm", function() stm);
  124.     return stm;
  125.   },
  126.  
  127.   get _urlStm() {
  128.     this._log.trace("Creating SQL statement: _urlStm");
  129.     let stm = this._db.createStatement(
  130.       "SELECT url, title, frecency " +
  131.       "FROM moz_places_view " +
  132.       "WHERE id = (" +
  133.         "SELECT place_id " +
  134.         "FROM moz_annos " +
  135.         "WHERE content = :guid AND anno_attribute_id = (" +
  136.           "SELECT id " +
  137.           "FROM moz_anno_attributes " +
  138.           "WHERE name = '" + GUID_ANNO + "'))");
  139.     this.__defineGetter__("_urlStm", function() stm);
  140.     return stm;
  141.   },
  142.  
  143.   // See bug 320831 for why we use SQL here
  144.   _getVisits: function HistStore__getVisits(uri) {
  145.     let visits = [];
  146.     if (typeof(uri) != "string")
  147.       uri = uri.spec;
  148.  
  149.     try {
  150.       this._visitStm.params.url = uri;
  151.       while (this._visitStm.step()) {
  152.         visits.push({date: this._visitStm.row.date,
  153.                      type: this._visitStm.row.type});
  154.       }
  155.     } finally {
  156.       this._visitStm.reset();
  157.     }
  158.  
  159.     return visits;
  160.   },
  161.  
  162.   // See bug 468732 for why we use SQL here
  163.   _findURLByGUID: function HistStore__findURLByGUID(guid) {
  164.     try {
  165.       this._urlStm.params.guid = guid;
  166.       if (!this._urlStm.step())
  167.         return null;
  168.  
  169.       return {
  170.         url: this._urlStm.row.url,
  171.         title: this._urlStm.row.title,
  172.         frecency: this._urlStm.row.frecency
  173.       };
  174.     }
  175.     finally {
  176.       this._urlStm.reset();
  177.     }
  178.   },
  179.  
  180.   changeItemID: function HStore_changeItemID(oldID, newID) {
  181.     setGUID(this._findURLByGUID(oldID).url, newID);
  182.   },
  183.  
  184.  
  185.   getAllIDs: function HistStore_getAllIDs() {
  186.     let query = this._hsvc.getNewQuery(),
  187.         options = this._hsvc.getNewQueryOptions();
  188.  
  189.     query.minVisits = 1;
  190.     options.maxResults = 1000;
  191.     options.sortingMode = options.SORT_BY_DATE_DESCENDING;
  192.     options.queryType = options.QUERY_TYPE_HISTORY;
  193.  
  194.     let root = this._hsvc.executeQuery(query, options).root;
  195.     root.QueryInterface(Ci.nsINavHistoryQueryResultNode);
  196.     root.containerOpen = true;
  197.  
  198.     let items = {};
  199.     for (let i = 0; i < root.childCount; i++) {
  200.       let item = root.getChild(i);
  201.       let guid = GUIDForUri(item.uri, true);
  202.       items[guid] = item.uri;
  203.     }
  204.     return items;
  205.   },
  206.  
  207.   create: function HistStore_create(record) {
  208.     // Add the url and set the GUID
  209.     this.update(record);
  210.     setGUID(record.histUri, record.id);
  211.   },
  212.  
  213.   remove: function HistStore_remove(record) {
  214.     let page = this._findURLByGUID(record.id)
  215.     if (page == null) {
  216.       this._log.debug("Page already removed: " + record.id);
  217.       return;
  218.     }
  219.  
  220.     let uri = Utils.makeURI(page.url);
  221.     Svc.History.removePage(uri);
  222.     this._log.trace("Removed page: " + [record.id, page.url, page.title]);
  223.   },
  224.  
  225.   update: function HistStore_update(record) {
  226.     this._log.trace("  -> processing history entry: " + record.histUri);
  227.  
  228.     let uri = Utils.makeURI(record.histUri);
  229.     if (!uri) {
  230.       this._log.warn("Attempted to process invalid URI, skipping");
  231.       throw "invalid URI in record";
  232.     }
  233.     let curvisits = [];
  234.     if (this.urlExists(uri))
  235.       curvisits = this._getVisits(record.histUri);
  236.  
  237.     // Add visits if there's no local visit with the same date
  238.     for each (let {date, type} in record.visits)
  239.       if (curvisits.every(function(cur) cur.date != date))
  240.         Svc.History.addVisit(uri, date, null, type, type == 5 || type == 6, 0);
  241.  
  242.     this._hsvc.setPageTitle(uri, record.title);
  243.   },
  244.  
  245.   itemExists: function HistStore_itemExists(id) {
  246.     if (this._findURLByGUID(id))
  247.       return true;
  248.     return false;
  249.   },
  250.  
  251.   urlExists: function HistStore_urlExists(url) {
  252.     if (typeof(url) == "string")
  253.       url = Utils.makeURI(url);
  254.     // Don't call isVisited on a null URL to work around crasher bug 492442.
  255.     return url ? this._hsvc.isVisited(url) : false;
  256.   },
  257.  
  258.   createRecord: function HistStore_createRecord(guid, cryptoMetaURL) {
  259.     let foo = this._findURLByGUID(guid);
  260.     let record = new HistoryRec();
  261.     record.id = guid;
  262.     if (foo) {
  263.       record.histUri = foo.url;
  264.       record.title = foo.title;
  265.       record.sortindex = foo.frecency;
  266.       record.visits = this._getVisits(record.histUri);
  267.       record.encryption = cryptoMetaURL;
  268.     }
  269.     else
  270.       record.deleted = true;
  271.     this.cache.put(guid, record);
  272.     return record;
  273.   },
  274.  
  275.   wipe: function HistStore_wipe() {
  276.     this._hsvc.removeAllPages();
  277.   }
  278. };
  279.  
  280. function HistoryTracker() {
  281.   this._init();
  282. }
  283. HistoryTracker.prototype = {
  284.   __proto__: Tracker.prototype,
  285.   name: "history",
  286.   _logName: "HistoryTracker",
  287.   file: "history",
  288.  
  289.   QueryInterface: XPCOMUtils.generateQI([
  290.     Ci.nsINavHistoryObserver,
  291.     Ci.nsINavHistoryObserver_MOZILLA_1_9_1_ADDITIONS
  292.   ]),
  293.  
  294.   get _hsvc() {
  295.     let hsvc = Cc["@mozilla.org/browser/nav-history-service;1"].
  296.       getService(Ci.nsINavHistoryService);
  297.     this.__defineGetter__("_hsvc", function() hsvc);
  298.     return hsvc;
  299.   },
  300.  
  301.   _init: function HT__init() {
  302.     Tracker.prototype._init.call(this);
  303.     this._hsvc.addObserver(this, false);
  304.   },
  305.  
  306.   onBeginUpdateBatch: function HT_onBeginUpdateBatch() {},
  307.   onEndUpdateBatch: function HT_onEndUpdateBatch() {},
  308.   onPageChanged: function HT_onPageChanged() {},
  309.   onTitleChanged: function HT_onTitleChanged() {},
  310.  
  311.   /* Every add or remove is worth 1 point.
  312.    * Clearing the whole history is worth 50 points (see below)
  313.    */
  314.   _upScore: function BMT__upScore() {
  315.     this.score += 1;
  316.   },
  317.  
  318.   onVisit: function HT_onVisit(uri, vid, time, session, referrer, trans) {
  319.     if (this.ignoreAll)
  320.       return;
  321.     this._log.trace("onVisit: " + uri.spec);
  322.     if (this.addChangedID(GUIDForUri(uri, true)))
  323.       this._upScore();
  324.   },
  325.   onPageExpired: function HT_onPageExpired(uri, time, entry) {
  326.   },
  327.   onBeforeDeleteURI: function onBeforeDeleteURI(uri) {
  328.     if (this.ignoreAll)
  329.       return;
  330.     this._log.trace("onBeforeDeleteURI: " + uri.spec);
  331.     if (this.addChangedID(GUIDForUri(uri, true)))
  332.       this._upScore();
  333.   },
  334.   onDeleteURI: function HT_onDeleteURI(uri) {
  335.   },
  336.   onClearHistory: function HT_onClearHistory() {
  337.     this._log.trace("onClearHistory");
  338.     this.score += 500;
  339.   }
  340. };
  341.